C++ 容器

容器

顺序容器

  • std::vector (可变数组)

  • 声明 vector<int> myVector {1,2,3};

  • 访问元素 myVector[2], 不检查是否越界

  • 修改指定位置 myVector[2] = 33;

  • 如果把一个对象存入容器中,那么容器将存储该对象的副本

  • vector 的析构函数执行时,会调用容器中每个对象的析构函数

  • push_back:

    1
    2
    3
    std::vector<int> numbers;
    numbers.push_back(1);
    numbers.push_back(2);
  • pop_back:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    numbers.pop_back();
  • size:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    std::cout << "Size: " << numbers.size() << std::endl;
  • at:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    int value = numbers.at(1); // 获取索引为1的元素值
  • front:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    int firstValue = numbers.front(); // 获取第一个元素值
  • back:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    int lastValue = numbers.back(); // 获取最后一个元素值
  • clear:

    1
    2
    std::vector<int> numbers = {1, 2, 3};
    numbers.clear(); // 清空所有元素
  • erase:

    1
    2
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    numbers.erase(numbers.begin() + 2); // 删除索引为2的元素
  • insert: insert 插入比如使用 myVector.begin() 返回 iterator 明确插入元素位置,不能直接使用数字

    1
    2
    3

    std::vector<int> numbers = {1, 2, 3, 4, 5};
    numbers.insert(numbers.begin() + 2, 99); // 在索引为2的位置插入值为99的元素
  • empty:

1
2
3
4
5

std::vector<int> numbers;
if (numbers.empty()) {
std::cout << "Vector is empty." << std::endl;
}
  • reserve:
1
2
std::vector<int> numbers;
numbers.reserve(10); // 预留空间,但不改变 size
  • resize:
1
2
std::vector<int> numbers = {1, 2, 3};
numbers.resize(5); // 将容器的大小调整为5,多余的元素填充默认值
  • 遍历容器
1
2
3
for (auto& item:myVector) {
cout << item << endl;
}

其他顺序容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <list>
#include <vector>
#include <deque>

// forward_list 单向链表
list<int> myList; // 双向链表容器
myList.push_back(1);
myList.push_back(2);
myList.push_back(3);
//没办法执行myList.begin()+2这样的操作
myList.insert(++myList.begin(), 7);

deque<int> myDeque; // 双端队列
myDeque.push_back(1);
myDeque.push_front(1);
myDeque.push_back(2);
myDeque.push_back(3);
myDeque.insert(myDeque.begin()+2, 2);

容器适配器

队列和栈(对 deque 的包装)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <queue>
#include <stack>
using namespace std;

int main() {
//队列容器(先进先出)
queue<int> myQueue;
myQueue.push(1);
myQueue.push(2);
myQueue.push(3);
do {
cout << myQueue.front() << endl; //输出 1 2 3
myQueue.pop();
} while (myQueue.size() > 0);

//堆栈容器(后进先出)
stack<int> myStack;
myStack.push(1);
myStack.push(2);
myStack.push(3);
do {
cout << myStack.top() << endl; //输出 3 2 1
myStack.pop();
} while (myStack.size() > 0);

auto c = getchar();
}

关联容器

  • map 容器用于保存一系列的键值对数据,与 JavaScript 中的 Map 功用相似

  • 包含头文件:

    1
    #include <map>
  • 定义 std::map 对象:

    1
    std::map<KeyType, ValueType> myMap;

    其中,KeyType 是键的数据类型,ValueType 是值的数据类型。

  • 插入键值对:

    1
    myMap[key] = value;  // 或者 myMap.insert(std::make_pair(key, value));
  • 访问元素:

    1
    ValueType value = myMap[key];
  • 遍历 std::map

    1
    2
    3
    4
    5
    for (const auto& pair : myMap) {
    KeyType key = pair.first;
    ValueType value = pair.second;
    // 处理键值对
    }
  • 查找元素:

    1
    2
    3
    4
    5
    6
    7
    auto it = myMap.find(key);
    if (it != myMap.end()) {
    // 找到了
    ValueType value = it->second;
    } else {
    // 未找到
    }
  • 删除元素:

    1
    myMap.erase(key);
  • 判断是否为空:

    1
    2
    3
    if (myMap.empty()) {
    // map 为空
    }
  • 合并 map

    1
    2
    3
    map<string, string> myMap1{ {"key1","val1"},{"key2","val2"} };
    map<string, string> myMap2{ {"key3","val3"},{"key4","val4"} };
    myMap1.merge(myMap2);
  • 获取元素个数:

    1
    size_t size = myMap.size();
  • 清空 std::map

    1
    myMap.clear();
  • 自定义比较函数: 如果键类型不支持比较操作,或者需要自定义排序方式,可以提供一个比较函数或者使用函数对象。

    1
    std::map<KeyType, ValueType, CompareFunction> myMap;

其中,CompareFunction 是用于比较键的函数或者函数对象。

  • 遍历 map

    1
    2
    3
    4
    5
    6
    //遍历map容器,
    //keyval是pair<string,string>类型的对象,
    //pair模板可以将两个不同类型的值组合起来
    for (const auto& keyval: myMap) {
    cout << keyval.first << ":" << keyval.second << endl;
    }
  • sset 容器用于存储一系列不重复的元素(不是键值对),与 JavaScript 中的 Set 功用相似

  • set 接口几乎与 map 相同,主要区别是 set 没有下标操作符(operator[])、insert_or_assign 和 try_emplace 等接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    int main() {
    set<int> s {1,2,3};
    //不会被插入,也不会报错,因为set容器中已经包含了元素3
    s.insert(3);
    cout << s.size() << endl; //输出3
    // 遍历
    for (auto& item:s) {
    cout << item << endl; //输出 1,2,3
    }
    //移除元素3,不是移除第三个位置的元素
    s.erase(3);
    //获取最后一个元素
    cout << *(--s.end()) << endl; //输出2
    s.clear();
    return 0;
    }
  • multiset 和 multimap 允许存储多个相同的元素

无序关联容器

  • unordered_mapunordered_multimapunordered_setunordered_multiset
  • ,无序关联容器内存储的元素是无序的,元素在容器中的位置由键的哈希值确定
  • 无序关联容器获取指定的元素会比普通关联容器要快,但要遍历迭代整个无序关联容器效率则没有普通关联容器好。

元组

用于存储多个元素,每个元素的类型可以不同。元组提供了一个有序的集合,可以方便地将多个值组合在一起。

以下是一些关于元组的基本特点和用法:

  • 包含头文件:

    1
    #include <tuple>
  • 定义 std::tuple 对象:

    1
    std::tuple<T1, T2, ..., Tn> myTuple;  // 其中 T1, T2, ..., Tn 是元素的类型
  • 初始化元组:

    1
    auto myTuple = std::make_tuple(value1, value2, ..., valueN);
  • 访问元组元素:

    1
    std::get<Index>(myTuple);  // Index 是元素的索引,从 0 开始

    或者使用结构化绑定(C++17 及以上):

    1
    auto [var1, var2, ..., varN] = myTuple;
  • 修改元组元素:

    1
    std::get<Index>(myTuple) = newValue;
  • 获取元组大小:

    1
    constexpr std::size_t tupleSize = std::tuple_size<decltype(myTuple)>::value;
  • 比较元组:

    1
    bool isEqual = (tuple1 == tuple2);
  • 遍历元组:

    1
    std::apply([](auto&&... args) { /* 处理元组中的元素 */ }, myTuple);

元组在需要将多个相关的值一起传递或组织时非常有用,尤其是当值的类型不同或者数量不确定时。元组提供了一种更灵活的数据结构,可以在编译时或运行时动态地组织和访问元素。

作者

大下坡

发布于

2023-11-17

更新于

2023-11-17

许可协议